﻿using MikuMikuLibrary.Databases;
using MikuMikuLibrary.IO;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;

namespace DatabaseConverter
{
    class Program
    {
        static BinaryFile GetDatabaseInstance( string fileName )
        {
            fileName = Path.GetFileNameWithoutExtension( fileName ).ToLowerInvariant().Replace( "_", "" );

            if ( fileName.StartsWith( "mdata" ) )
                fileName = fileName.Substring( 5 );

            switch ( fileName )
            {
                case "aetdb":
                    return new AetDatabase();
                case "bonedata":
                    return new BoneDatabase();
                //case "editdb":
                //    return new EditDatabase()
                case "motdb":
                    return new MotionDatabase();
                case "objdb":
                    return new ObjectDatabase();
                case "sprdb":
                    return new SpriteDatabase();
                case "stagedata":
                    return new StageDatabase();
                case "strarray":
                case "stringarray":
                    return new StringArray();
                case "texdb":
                    return new TextureDatabase();
                default:
                    throw new ArgumentException( "Database type could not be detected", nameof( fileName ) );
            }
        }

        public static void Do( string[] args )
        {
            string sourceFileName = null;
            string destinationFileName = null;
            string mergeType = null;
            string sourceSprFilename = null;
            string destinationSprFilename = null;

            foreach ( var arg in args )
            {
                if (mergeType == null)
                    mergeType = arg;

                else if ( sourceFileName == null )
                    sourceFileName = arg;

                else if ( destinationFileName == null )
                    destinationFileName = arg;

                else if (sourceSprFilename == null)
                    sourceSprFilename = arg;

                else if (destinationSprFilename == null)
                    destinationSprFilename = arg;
            }

            if (mergeType != null)
            {
                if (mergeType == "aetsprmerge")
                {
                    Console.WriteLine("Spr and Aet Merge");
                    AetMerge aetMerge = new AetMerge();
                    aetMerge.db.Load(sourceFileName);
                    aetMerge.db2.Load(destinationFileName);

                    SprMerge sprMerge = new SprMerge();
                    sprMerge.db.Load(sourceSprFilename);
                    sprMerge.db2.Load(destinationSprFilename);
                    sprMerge.MergeAet();
                    aetMerge.MergeAet(sprMerge);

                    aetMerge.db.Save("merged_aet.bin");
                    sprMerge.db.Save("merged_spr.bin");

                    string sourceXmlFileName = Path.ChangeExtension(sourceFileName, "xml");
                    var serializer = new XmlSerializer(aetMerge.db.GetType());
                    using (var destination = File.CreateText(sourceXmlFileName))
                        serializer.Serialize(destination, aetMerge.db);
                } else

                if (mergeType == "objmerge")
                {
                    Console.WriteLine("Obj Merge");
                    ObjMerge aetMerge = new ObjMerge();
                    aetMerge.db.Load(sourceFileName);
                    aetMerge.db2.Load(destinationFileName);
                    aetMerge.MergeAet();
                    aetMerge.db.Objects.OrderBy(c => c.Id);
                    aetMerge.db.Save("merged_obj.bin");
                    Console.Write(aetMerge.logs);
                    File.WriteAllText("obj_logs", aetMerge.logs);
                    string sourceXmlFileName = Path.ChangeExtension(sourceFileName, "xml");
                    var serializer = new XmlSerializer(aetMerge.db.GetType());
                    using (var destination = File.CreateText(sourceXmlFileName))
                        serializer.Serialize(destination, aetMerge.db);

                } else

                if (mergeType == "objeffchr")
                {
                    Console.WriteLine("Obj EFFCHRPV");
                    ObjMerge aetMerge = new ObjMerge();
                    aetMerge.db.Load(sourceFileName);
                    aetMerge.db2.Load(destinationFileName);
                    aetMerge.MergeAet("", "effchr");
                    ObjectEntry[] cde = new ObjectEntry[aetMerge.db.Objects.Count];
                    aetMerge.db.Objects.CopyTo(cde);
                    var efg = new List<ObjectEntry>();
                    foreach (var k in cde)
                    {
                        efg.Add(k);
                    }
                    var dbs = efg.OrderBy(c => c.Id);
                    aetMerge.db.Objects.Clear();
                    foreach (var obj in efg)
                    {
                        aetMerge.db.Objects.Add(obj);
                    }
                    aetMerge.db.Save("merged_obj.bin");
                    Console.Write(aetMerge.logs);
                    string sourceXmlFileName = Path.ChangeExtension(sourceFileName, "xml");
                    var serializer = new XmlSerializer(aetMerge.db.GetType());
                    using (var destination = File.CreateText(sourceXmlFileName))
                        serializer.Serialize(destination, aetMerge.db);

                }
                else

                if (mergeType == "motmerge")
                {
                    Console.WriteLine("Mot Merge");
                    MotMerge aetMerge = new MotMerge();
                    aetMerge.db.Load(sourceFileName);
                    aetMerge.db2.Load(destinationFileName);
                    aetMerge.MergeAet();
                    aetMerge.db.Save("merged_mot.bin");

                    string sourceXmlFileName = Path.ChangeExtension(sourceFileName, "xml");
                    var serializer = new XmlSerializer(aetMerge.db.GetType());
                    using (var destination = File.CreateText(sourceXmlFileName))
                        serializer.Serialize(destination, aetMerge.db);

                } else

                if (mergeType == "texmerge")
                {
                    Console.WriteLine("Tex Merge");
                    TexMerge aetMerge = new TexMerge();
                    aetMerge.db.Load(sourceFileName);
                    aetMerge.db2.Load(destinationFileName);
                    aetMerge.MergeAet();
                    aetMerge.db.Textures.OrderBy(c => c.Id);
                    aetMerge.db.Save("merged_tex.bin");
                    Console.Write(aetMerge.logs);
                    string sourceXmlFileName = Path.ChangeExtension(sourceFileName, "xml");
                    var serializer = new XmlSerializer(aetMerge.db.GetType());
                    using (var destination = File.CreateText(sourceXmlFileName))
                        serializer.Serialize(destination, aetMerge.db);

                } else

                if (mergeType == "stagemerge")
                {
                    Console.WriteLine("Stage Merge");
                    StageMerge aetMerge = new StageMerge();
                    aetMerge.db.Load(sourceFileName);
                    aetMerge.db2.Load(destinationFileName);
                    aetMerge.MergeAet();
                    aetMerge.db.Save("merged_stage.bin");

                    string sourceXmlFileName = Path.ChangeExtension(sourceFileName, "xml");
                    var serializer = new XmlSerializer(aetMerge.db.GetType());
                    using (var destination = File.CreateText(sourceXmlFileName))
                        serializer.Serialize(destination, aetMerge.db);

                } else

                if (mergeType == "stagemerge")
                {
                    Console.WriteLine("Stage Merge");
                    StageMerge aetMerge = new StageMerge();
                    aetMerge.db.Load(sourceFileName);
                    aetMerge.db2.Load(destinationFileName);
                    aetMerge.MergeAet();
                    aetMerge.db.Save("merged_stage.bin");

                    string sourceXmlFileName = Path.ChangeExtension(sourceFileName, "xml");
                    var serializer = new XmlSerializer(aetMerge.db.GetType());
                    using (var destination = File.CreateText(sourceXmlFileName))
                        serializer.Serialize(destination, aetMerge.db);

                }
                else if (mergeType == "stagefix")
                {
                    Console.WriteLine("Stage Fix");
                    StageFix aetMerge = new StageFix();
                    aetMerge.db.Load(sourceFileName);
                    aetMerge.db_ac.Load(destinationFileName);
                    aetMerge.MergeAet();
                    aetMerge.db.Save("fixed_stage.bin");

                    Console.WriteLine(aetMerge.logs);
                    string sourceXmlFileName = Path.ChangeExtension(sourceFileName, "xml");
                    var serializer = new XmlSerializer(aetMerge.db.GetType());
                    using (var destination = File.CreateText(sourceXmlFileName))
                        serializer.Serialize(destination, aetMerge.db);

                } else

                if (mergeType == "aetsprfilter")
                {
                    Console.WriteLine("Spr and Aet Filter only PV");
                    AetFilter aetMerge = new AetFilter();
                    aetMerge.db.Load(sourceFileName);
                    aetMerge.db2.Load(destinationFileName);

                    SprFilter sprMerge = new SprFilter();
                    sprMerge.db.Load(sourceSprFilename);
                    sprMerge.db2.Load(destinationSprFilename);
                    aetMerge.MergeAet();
                    sprMerge.MergeAet(aetMerge);
                    
                    aetMerge.db.Save("merged_aet2.bin");
                    sprMerge.db.Save("merged_spr2.bin");

                    string sourceXmlFileName = Path.ChangeExtension(sourceFileName, "xml");
                    var serializer = new XmlSerializer(aetMerge.db.GetType());
                    using (var destination = File.CreateText(sourceXmlFileName))
                        serializer.Serialize(destination, aetMerge.db);
                }

                else
                {
                    Console.WriteLine("Convert to XML/Bin");
                    foreach (var arg in args)
                    {
                        if (sourceFileName == null)
                            sourceFileName = arg;

                        else if (destinationFileName == null)
                            destinationFileName = arg;
                    }
                    
                    if (destinationFileName == null)
                        destinationFileName = sourceFileName;

                    if (sourceFileName.EndsWith(".bin", StringComparison.OrdinalIgnoreCase))
                    {
                        destinationFileName = Path.ChangeExtension(destinationFileName, "xml");

                        var database = GetDatabaseInstance(sourceFileName);
                        database.Load(sourceFileName);

                        var serializer = new XmlSerializer(database.GetType());
                        using (var destination = File.CreateText(destinationFileName))
                            serializer.Serialize(destination, database);
                    }
                    else if (sourceFileName.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
                    {
                        destinationFileName = Path.ChangeExtension(destinationFileName, "bin");

                        var database = GetDatabaseInstance(sourceFileName);

                        var serializer = new XmlSerializer(database.GetType());
                        using (var source = File.OpenText(sourceFileName))
                            database = (BinaryFile)serializer.Deserialize(source);

                        database.Save(destinationFileName);
                    }
                }

            }
            else
            {
            }
        }
    }
}
